// -*- C++ -*-
#ifndef SATTRIBUTE_H
#define SATTRIBUTE_H

#include <vector>
#include <string>
#include <iterator>
#include <algorithm>

namespace sds {
  class SAttribute;
}

#include "sutility.h"
#include "sdatatype.h"

namespace sds {

  class SAttribute {
    friend class SFile;
    friend class SDataset;
  public:

    ~SAttribute();

    const std::string& getName() const { return name; }
    SDataType getDataType() const { return dataType; }

    template <typename Type, typename Container>
    Container getData() const;

    template <typename Type>
    std::vector<Type> getData() const {
      return getData<Type, std::vector<Type> >();
    }

  private:

    template <typename Type, typename Container, typename T>
    void readData(Container&) const;

    void readBuffer(void*) const;

    SAttribute(int fileId, int index);

    SInteger fileId;
    SInteger index;
    std::string name;
    SDataType dataType;
    SInteger length;
  };

  template <typename Type, typename Container>
  Container SAttribute::getData() const {
    Container container;
    switch (dataType) {
    case CHAR:
      readData<Type, Container, char>(container);
      break;
    case UCHAR:
      readData<Type, Container, unsigned char>(container);    
      break;
    case INT8:
      readData<Type, Container, char>(container);    
      break;
    case UINT8:
      readData<Type, Container, unsigned char>(container);    
      break;
    case INT16:
      readData<Type, Container, short>(container);    
      break;
    case UINT16:
      readData<Type, Container, unsigned short>(container);    
      break;
    case INT32:
      readData<Type, Container, long>(container);    
      break;
    case UINT32:
      readData<Type, Container, unsigned long>(container);    
      break;
    case INT64:
      readData<Type, Container, long long>(container);    
      break;
    case UINT64:
      readData<Type, Container, unsigned long long>(container);    
      break;
    case FLOAT32:
      readData<Type, Container, float>(container);    
      break;
    case FLOAT64:
      readData<Type, Container, double>(container);    
      break;
    default:
      break;
    }
    return container;
  }
  
  template <typename Type, typename Container, typename T>
  void SAttribute::readData(Container& container) const {
    T* data = 0;
    try {
      data = new T[length];
      readBuffer((void*)data);
      std::transform(data, data + length, 
		     std::back_inserter(container), _SConverter<Type, T>());
      delete[] data;
    } catch (...) {
      if (data) delete[] data;
    }
  }
}

#endif
